package com.scy.asm.hello;

import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;

/**
 * 代码生成
 */
public class HelloWorldGenerator {

    /**
     * 生成class
     *
     * @return
     */
    public static byte[] generateHelloWorldClass() {
        // 创建一个 ClassWriter 实例，用于生成字节码，COMPUTE_FRAMES 表示自动计算堆栈大小和局部变量表
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

        // 定义类信息
        // V1_8: Java 8 版本
        // ACC_PUBLIC: 公共类修饰符
        // "HelloWorld": 类的名称
        // "java/lang/Object": 该类的父类
        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "HelloWorld", null, "java/lang/Object", null);

        // 定义构造方法
        // ACC_PUBLIC: 公共方法修饰符
        // "<init>": 构造方法名称
        // "()V": 方法签名，表示该方法无参数，返回值为 void
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);

        // 开始生成方法字节码
        mv.visitCode();

        // 将 "this" 变量加载到操作数栈中，位置为 0 的局部变量
        mv.visitVarInsn(Opcodes.ALOAD, 0);

        // 调用父类的构造方法 "java/lang/Object.<init>()V"
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);

        // 从方法中返回，结束构造方法
        mv.visitInsn(Opcodes.RETURN);

        // 设置操作数栈和局部变量表的最大大小
        mv.visitMaxs(1, 1);

        // 结束构造方法的字节码生成
        mv.visitEnd();

        // 定义 main 方法
        // ACC_PUBLIC + ACC_STATIC: 公共静态方法修饰符
        // "main": 方法名称
        // "([Ljava/lang/String;)V": 方法签名，表示参数是一个字符串数组，返回值为 void
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);

        // 开始生成方法字节码
        mv.visitCode();

        // 获取 System.out 字段，类型为 PrintStream，压入操作数栈
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

        // 将 "Hello, ASM!" 字符串常量压入操作数栈
        mv.visitLdcInsn("Hello, ASM!");

        // 调用 PrintStream.println(String) 方法，打印栈顶的字符串
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

        // 从方法中返回，结束 main 方法
        mv.visitInsn(Opcodes.RETURN);

        // 设置操作数栈和局部变量表的最大大小
        mv.visitMaxs(2, 2);

        // 结束 main 方法的字节码生成
        mv.visitEnd();

        // 结束类的字节码生成
        cw.visitEnd();

        // 返回生成的字节码数组
        return cw.toByteArray();
    }
}
